// Copyright 2022 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.

package rpc

import (
	"bytes"
	"fmt"
	"io"
	"testing"

	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
	"github.com/stretchr/testify/require"
)

func TestSnappyCompressorCompressDecompress(t *testing.T) {
	defer leaktest.AfterTest(t)()
	var c snappyCompressor
	for _, tt := range []struct {
		in     []byte // uncompressed
		expOut []byte // compressed
	}{
		{[]byte("A"), []byte{0xff, 0x6, 0x0, 0x0, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59, 0x1, 0x5, 0x0, 0x0, 0xb3, 0xad, 0x60, 0x3e, 0x41, 0xb0, 0x1, 0x0, 0x0, 0x1}},
		{[]byte("ABC"), []byte{0xff, 0x6, 0x0, 0x0, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59, 0x1, 0x7, 0x0, 0x0, 0x4b, 0xfb, 0x81, 0xf5, 0x41, 0x42, 0x43, 0xb0, 0x1, 0x0, 0x0, 0x3}},
	} {
		t.Run(fmt.Sprintf("input=%v", tt.in), func(t *testing.T) {
			// Compress.
			buf := &bytes.Buffer{}
			wc, err := c.Compress(buf)
			require.NoError(t, err)

			_, err = wc.Write(tt.in)
			require.NoError(t, err)
			err = wc.Close()
			require.NoError(t, err)
			out := buf.Bytes()
			require.Equal(t, tt.expOut, out)

			// Decompress.
			n := c.DecompressedSize(out)
			require.Equal(t, len(tt.in), n)

			r, err := c.Decompress(bytes.NewReader(out))
			require.NoError(t, err)
			in, err := io.ReadAll(r)
			require.NoError(t, err)
			require.EqualValues(t, tt.in, in)
		})
	}
}

func TestSnappyCompressorDecompressedSize(t *testing.T) {
	defer leaktest.AfterTest(t)()
	var c snappyCompressor
	for _, tt := range []struct {
		name string
		in   []byte // compressed
		exp  int
	}{
		{"present", []byte{0xff, 0x6, 0x0, 0x0, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59, 0x1, 0x7, 0x0, 0x0, 0x4b, 0xfb, 0x81, 0xf5, 0x41, 0x42, 0x43, 0xb0, 0x1, 0x0, 0x0, 0x3}, 3},
		{"missing", []byte{0xff, 0x6, 0x0, 0x0, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59, 0x1, 0x7, 0x0, 0x0, 0x4b, 0xfb, 0x81, 0xf5, 0x41, 0x42, 0x43}, -1},
		{"corrupt prior chunk", []byte{0xff, 0x7, 0x0, 0x0, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59, 0x1, 0x7, 0x0, 0x0, 0x4b, 0xfb, 0x81, 0xf5, 0x41, 0x42, 0x43, 0xb0, 0x1, 0x0, 0x0, 0x3}, -1},
		{"corrupt length chunk", []byte{0xff, 0x6, 0x0, 0x0, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59, 0x1, 0x7, 0x0, 0x0, 0x4b, 0xfb, 0x81, 0xf5, 0x41, 0x42, 0x43, 0xb0, 0x2, 0x0, 0x0, 0x3}, -1},
	} {
		t.Run(fmt.Sprintf("input=%v", tt.in), func(t *testing.T) {
			n := c.DecompressedSize(tt.in)
			require.Equal(t, tt.exp, n)
		})
	}
}
